import type { App, VNode, Directive, DirectiveBinding } from 'vue'
import loading from './index.vue'
import { createVNode, render } from 'vue'


const createdLoading = () => {
    // 将vue组件转换成一个vnode对象
    const loadingVnode: VNode = createVNode(loading)

    const show: any = (el: HTMLElement) => {
        if (el) {
            // 将loading挂载到父级元素中，父级元素必须要有position，且为fixed、 absolute 或 relative
            // 判断是否有position属性，并获取值
            const position = getComputedStyle(el, null).position
            if (position === 'static') {
                el.style.position = 'relative'
            } else if (position !== 'relative' && position !== 'absolute' && position !== 'fixed') {
                console.warn('loading元素的position必须为fixed、 absolute 或 relative')
            }
            // 挂载loading节点到el节点下
            render(loadingVnode, el)
        } else {
            // 没有指定节点挂载vnode到body节点中
            render(loadingVnode, document.body)
        }
        loadingVnode.component?.exposed?.show()
    }

    const hide = () => {
        loadingVnode.component?.exposed?.hide()
    }

    return {
        show,
        hide
    }
}


type bglod = {
    show: (el?:HTMLElement) => void,
    hide: () => void
} 

export default {
    install(app: App) {
        
        const loading = createdLoading()
        // 获取到组件暴露的方法，并挂载到app上
        app.config.globalProperties.$bgLoading = {
            show: loading.show,
            hide: loading.hide
        }

        // 使用指令loading时，可能存在一个页面有多个loading。使用集合对这些loading进行收集
        const loadingMap = new WeakMap<HTMLElement, bglod>()
        // 定义loading指令
        const vBgloading: Directive = (el:HTMLElement, binding:DirectiveBinding) => {
            let nowLoading = loadingMap.get(el)  // 查找是否有现成的loading
            if (!nowLoading) {  // 如果当前loading不存在，新建loading
                nowLoading = createdLoading()
                loadingMap.set(el, nowLoading)
            }
            if (binding.value === true || binding.value === 'true') {
                nowLoading.show(el)
            } else {
                nowLoading.hide()
            }

        }
        
        // 将指令挂载到app上
        app.directive('Bgloading', vBgloading)

    }
}